<template>
  <view>
  </view>
</template>

<script lang="uts">
  /**
   * 引用 Android 系统库
   * [可选实现，按需引入]
   */
  import TextUtils from 'android.text.TextUtils';
  import WebView from 'android.webkit.WebView';
  import WebViewClient from 'android.webkit.WebViewClient';
  import WebResourceRequest from 'android.webkit.WebResourceRequest'
  import WebResourceError from 'android.webkit.WebResourceError'
  import LinearLayout from 'android.widget.LinearLayout'
  import Build from 'android.os.Build'
  
  class WebAppInterface {
  	  private comp : UTSComponent<WebView>;
  	  constructor(comp : UTSComponent<WebView>) {
  	    this.comp = comp;
  	  }
  	  postMessage(message: String): void  {
		  this.comp.$emit('message', message)
      }
  }
  
  /**
   * 定义webview事件
   * [可选实现]
   */
  class MyWebViewClient extends WebViewClient {
  	private comp : UTSComponent<WebView>;
  	constructor(comp : UTSComponent<WebView>) {
  	  super();
  	  this.comp = comp;
  	}
    // 拦截 URL 加载
    override shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): boolean {
		const url = request.getUrl().toString()
		console.log('url', url);
		const head = ["http", "https", "file"]//允许特定特步协议通过
		const valid = !head.some((h: string): boolean => url.startsWith(h))
		return valid
      
      // return true 拦截 WebView 加载
      // return false 允许 WebView 加载
    }
    
    // 页面加载完成
    override onPageFinished(view: WebView, url: string): void {
  	  super.onPageFinished(view, url)
      // 示例：注入 JavaScript
  	  const jsCode =  `
  	  javascript:(function() { 
  	    var title = document.title;
  	    var href = window.location.href
  	    var head = document.head;
  	    var links = head.querySelectorAll('link[rel="icon"], link[rel="shortcut icon"]');
  	    var favicon = links.length > 0 ? links[0].href : href + (href.substring(href.length -1) == '/' ? '' : '/') + 'favicon.ico'
  	    return { title, href, favicon }
  	  })();
  	  `
  	  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
  	      view.evaluateJavascript(jsCode, (value: string) => {
  			this.comp.$emit("loaded", JSON.parse(value) as UTSJSONObject);
  		  })
  	  } else {
  	      view.loadUrl(jsCode)
  	  }
    }
    
    // 处理加载错误
    override onReceivedError(view: WebView, request: WebResourceRequest, error: WebResourceError): void {
	  const errorCode = error.errorCode
	  // if (errorCode == -6 /* ANDROID_BAD_URL_ERROR */ || errorCode == -2 /* ERROR_UNSUPPORTED_SCHEME */) {
	  //     // 处理不支持的URL或格式等错误
	  // } else if (errorCode == -104 /* ERROR_FILE_NOT_FOUND */ || errorCode == -113 /* ERROR_HOST_LOOKUP */) {
	  //     // 处理文件未找到或主机查找失败等错误
	  // } else {
	  //     // 其他错误处理
	  // }
   //    // 显示错误页面 (示例)
   //    const html = `<html><body><h1>加载失败</h1><p>${error.toString()}</p></body></html>`
   //    view.loadData(html, "text/html", "UTF-8")
  	  //错误回调
  	  this.comp.$emit("error", {
		errorCode: errorCode,
  	  	error: error.toString(),
  	  	failingUrl: request.getUrl().toString()
  	  });
    }
  }

  /**
   * 引入三方库
   * [可选实现，按需引入]
   *
   * 在 Android 平台引入三方库有以下两种方式：
   * 1、[推荐] 通过 仓储 方式引入，将 三方库的依赖信息 配置到 config.json 文件下的 dependencies 字段下。详细配置方式[详见](https://uniapp.dcloud.net.cn/plugin/uts-plugin.html#dependencies)
   * 2、直接引入，将 三方库的aar或jar文件 放到libs目录下。更多信息[详见](https://uniapp.dcloud.net.cn/plugin/uts-plugin.html#android%E5%B9%B3%E5%8F%B0%E5%8E%9F%E7%94%9F%E9%85%8D%E7%BD%AE)
   *
   * 在通过上述任意方式依赖三方库后，使用时需要在文件中 import
   * import { LottieAnimationView } from 'com.airbnb.lottie.LottieAnimationView'
   */

  /**
   * UTSAndroid 为平台内置对象，不需要 import 可直接调用其API，[详见](https://uniapp.dcloud.net.cn/uts/utsandroid.html#utsandroid)
   */

  //原生提供以下属性或方法的实现
  export default {
    /**
     * 组件名称，也就是开发者使用的标签
     */
    name: "ybuts-webview",
    /**
     * 组件涉及的事件声明，只有声明过的事件，才能被正常发送
     */
    emits: ['error', 'loaded', 'message'],
    /**
     * 属性声明，组件的使用者会传递这些属性值到组件
     */
    props: {
      "src": {
        type: String,
        default: ""
      }
    },
    /**
     * 组件内部变量声明
     */
    data() {
      return {}
    },
    /**
     * 属性变化监听器实现
     */
    watch: {
      "src": {
        /**
         * 这里监听属性变化，并进行组件内部更新
         */
        handler(newValue : string) {
			// try{
			// 	console.log('newVal', UTSAndroid.convert2AbsFullPath(newValue));
			// }catch(e){
			// 	console.log('err', e);
			// 	//TODO handle the exception
			// }
          if (!TextUtils.isEmpty(newValue)) {
			  this.$el?.loadUrl(newValue)
          }
        },
        immediate: false // 创建时是否通过此方法更新属性，默认值为false
      }
    },
    /**
     * 规则：如果没有配置expose，则methods中的方法均对外暴露，如果配置了expose，则以expose的配置为准向外暴露
     * ['publicMethod'] 含义为：只有 `publicMethod` 在实例上可用
     */
    expose: ['evalJS'],
    methods: {
      /**
       * 对外公开的组件方法
       *
       * uni-app中调用示例：
       * this.$refs["组件ref"].doSomething("uts-button");
       *
       * uni-app x中调用示例：
       * 1、引入对应Element
       * import { UtsButtonElement(组件名称以upper camel case方式命名 + Element) } from 'uts.sdk.modules.utsComponent(组件目录名称以lower camel case方式命名)';
       * 2、(this.$refs["组件ref"] as UtsButtonElement).doSomething("uts-button");
       * 或 (uni.getElementById("组件id") as UtsButtonElement).doSomething("uts-button");
       */
      evalJS(jsCode : string) {
		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
			this.$el?.post(() => {//webview的方法必须在主线程里执行，需要使用post
				this.$el?.evaluateJavascript("javascript:" + jsCode, (value: string) => {
					if ( value != 'null' ) this.$emit('message', value )
				})
			})
		} else {
		    this.$el?.loadUrl("javascript:" + jsCode)
		}
      },
      /**
       * 内部使用的组件方法
       */
      privateMethod() {

      }
    },
    /**
     * [可选实现] 组件被创建，组件第一个生命周期，
     * 在内存中被占用的时候被调用，开发者可以在这里执行一些需要提前执行的初始化逻辑
     */
    created() {
    },
    /**
     * [可选实现] 对应平台的view载体即将被创建，对应前端beforeMount
     */
    NVBeforeLoad() {

    },
    /**
     * [必须实现] 创建原生View，必须定义返回值类型
     * 开发者需要重点实现这个函数，声明原生组件被创建出来的过程，以及最终生成的原生组件类型
     * （Android需要明确知道View类型，需特殊校验）
     */
    NVLoad() : WebView {
	  const webView = new WebView($androidContext!);
	  webView.setLayoutParams(new LinearLayout.LayoutParams(
	      LinearLayout.LayoutParams.MATCH_PARENT,
	      LinearLayout.LayoutParams.MATCH_PARENT
	  ));
	  // 3. 配置WebView
	  const settings = webView.getSettings();
	  settings.setJavaScriptEnabled(true); // 启用JavaScript
	  settings.setDomStorageEnabled(true); // 启用DOM存储
	// 允许自动播放的配置
	  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
	      // API 级别 17+ - 媒体内容不需要用户手势即可播放
	      settings.setMediaPlaybackRequiresUserGesture(false)
	  }
	  // 其他推荐设置
	  settings.setAllowContentAccess(true)
	  settings.setAllowFileAccess(true)
	  // 防止用外部浏览器打开链接
	  webView.setWebViewClient(new MyWebViewClient(this));
	  webView.addJavascriptInterface(new WebAppInterface(this), "Android")
	  // 4. 加载网页
	  webView.loadUrl(this.src);
      return webView;
    },
    /**
     * [可选实现] 原生View已创建
     */
    NVLoaded() {

    },
    /**
     * [可选实现] 原生View布局完成
     */
    NVLayouted() {

    },
    /**
     * [可选实现] 原生View将释放
     */
    NVBeforeUnload() {
		this.$el?.destroy()
		super.destroy()
    },
    /**
     * [可选实现] 原生View已释放，这里可以做释放View之后的操作
     */
    NVUnloaded() {
    },
    /**
     * [可选实现] 组件销毁
     */
    unmounted() {
    },
    /**
     * [可选实现] 自定组件布局尺寸，用于告诉排版系统，组件自身需要的宽高
     * 一般情况下，组件的宽高应该是由终端系统的排版引擎决定，组件开发者不需要实现此函数
     * 但是部分场景下，组件开发者需要自己维护宽高，则需要开发者重写此函数
     */
    NVMeasure(size : UTSSize) : UTSSize {
      // size.width = 300.0.toFloat();
      // size.height = 200.0.toFloat();
      return size;
    }
  }
</script>

<style>

</style>